﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Framework.Event;
using NServiceBus;
using Framework.Infrastructure;
using Framework.Config;
using Microsoft.Practices.Unity;
using NServiceBus.Unicast;

namespace Framework.Bus
{
    class AsyncBusImpl : IAsyncBus<IMessage>
    {
        [Dependency("NSB")]
        public IBus Bus { get; set; }

        public AsyncBusImpl()
        {
            Config.Configuration.Instance.NServieBusBuild();
        }

        #region IBus<IMessage> Members

        public void Commit()
        {
            throw new NotImplementedException();
        }

        public void Publish(IMessage message)
        {
            Bus.Publish(message as Framework.Event.IDomainEvent);
        }

        public void Publish(IEnumerable<IMessage> messages)
        {
            Bus.Publish(messages.Cast<Framework.Event.IDomainEvent>().ToArray());
        }


        public void Send(IMessage message, Action action)
        {
            if (action != null)
            {
                AsyncCallback commandCallback = new AsyncCallback((target) =>
                {
                    var result = target.AsyncState as CompletionResult;
                    if (action != null && result.Messages != null && result.Messages.Length > 0)
                    {
                        action.Invoke();
                    }
                }
                );
                Bus.Send(message as Framework.Command.ICommand)
                   .Register(commandCallback, this).AsyncWaitHandle.WaitOne();
            }
            else
            {
                Send(message);
            }
        }

        public void Send(IMessage message)
        {
            Bus.Send(message as Framework.Command.ICommand);
        }

        public void Send<TResult>(IMessage message, Action<TResult> action = null)
        {
            if (action != null)
            {
                AsyncCallback _CommandCallback = new AsyncCallback((target) =>
                            {
                                var result = target.AsyncState as CompletionResult;

                                if (action != null)
                                {
                                    TResult tr = default(TResult);

                                    if (result.Messages != null && result.Messages.Length > 0)
                                    {
                                        tr = result.Messages[0].ToString().ToJsonObject<TResult>();
                                    }
                                    action.Invoke(tr);
                                }
                            }
                );
                Bus.Send(message as Framework.Command.ICommand)
                   .Register(_CommandCallback, this).AsyncWaitHandle.WaitOne();
            }
            else
            {
                Send(message);
            }
        }

        public void Send(IEnumerable<IMessage> messages)
        {
            Bus.Send(messages.Cast<Framework.Command.ICommand>().ToArray());
        }

        #endregion

        #region IDisposable Members

        public void Dispose()
        {
        }

        #endregion
    }
}
